package org.sbbs.base.jpa.manager.impl;

import cn.hutool.core.date.StopWatch;
import jakarta.annotation.Resource;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import net.oschina.j2cache.CacheChannel;
import org.sbbs.base.jpa.dao.BaseRepo;
import org.sbbs.base.jpa.entity.BaseEntity;
import org.sbbs.base.jpa.manager.BaseCacheManager;
import org.sbbs.base.jpa.manager.impl.BaseManagerImpl;
import org.springframework.cache.Cache;
import org.springframework.cache.Cache.ValueWrapper;
import org.springframework.cache.CacheManager;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.annotation.Transactional;

/**
 *
 * @author jenkins Manager体系原则上是负责实体数据管理功能
 * @param <T>
 * @param <ID>
 */
@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
@Transactional(readOnly = false, rollbackFor = Throwable.class)
public class BaseManagerCacheImpl<T extends BaseEntity, ID extends Serializable, R extends BaseRepo<T, ID>> extends BaseManagerImpl<T, ID, R> implements BaseCacheManager<T, ID, R> {

    @Resource
    private CacheChannel cacheChannel;

    /**
     * Spring CacheManager依赖
     */
    @Resource
    private CacheManager cacheManager;

    private Cache cache;

//    public BaseManagerCacheImpl(String cacheName) {
//        this.cacheManager.getCache(cacheName);
//    }
    @Override
    public T findById(ID id) {
        ValueWrapper vw = cache.get(id);
        if (vw != null) {
            log.debug("从缓存获取:{}key{}", this.cache.getName(), id);
            return (T) vw.get();
        } else {
            T t = super.findById(id);
            cache.put(id, t);
            log.debug("更新缓存:{}key{}", this.cache.getName(), t.getId());
            return t;
        }
    }

    @Override
    public T save(T entity) {
        T t = super.save(entity);
        cache.put(t.getId(), t);
        log.debug("更新缓存:{}key{}", this.cache.getName(), t.getId());
        return t;
    }

    @Override
    public boolean remove(T entity) {
        return this.removeById((ID) entity.getId());
    }

    @Override
    public boolean removeById(ID id) {
        boolean r = super.removeById(id);
        cache.evictIfPresent(id);
        log.debug("从缓存删除:{}key{}", this.cache.getName(), id);
        return r;
    }

    /**
     * Get a list of all the objects of the specified type.
     */
    @Override
    public List<T> findAll() {
        List<T> l = super.findAll();
        return l;
    }

    @Override
    public boolean existsById(ID id) {
        if (cache.get(id) != null) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public void removeAll(List<T> list) {

        super.removeAll(list);
        this.deleteCacheList(list);

    }

    @Override
    public Page<T> findAll(Pageable pageable) {

        List<T> l = new ArrayList<>();
        Page<?> p = super.findAllIds(pageable);
        List<?> ids = p.getContent();
        for (Object id : ids) {
            Cache.ValueWrapper t = this.getCache().get(id);
            if (t != null) {
                l.add((T) t.get());
            } else {
                T b = (T) super.findById((ID) id);
                this.getCache().put(id, b);
                log.debug("更新缓存:{}key{}", this.getCache().getName(), b.getId());
            }
        }
        ids = l;
        return (Page<T>) p;
    }

    @Override
    public List<T> findAllById(List<ID> ids) {
//        StopWatch sw = new StopWatch();
//        sw.start();

        List<T> l = new ArrayList<>();
        for (ID id : ids) {
            ValueWrapper t = cache.get(id);
            if (t != null) {
                l.add((T) t.get());
            }
        }
//        sw.stop();
//        log.debug("findAllById耗时:" + sw.getTotalTimeMillis());
        return l;
    }

    @Override
    public List<T> saveAll(List<T> entities) {
        List<T> l = super.saveAll(entities);
        for (T t : l) {
            cache.put(t.getId(), t);
        }
        return l;
    }

    @Override
    public void removeAllById(List<? extends ID> ids) {
        super.removeAllById(ids);
        this.deleteCacheIds(ids);
    }

    private void deleteCacheList(List<T> list) {
        log.debug("从缓存删除多缓存对象");
        for (T t : list) {
            cache.evictIfPresent(t.getId());
            log.debug("从缓存删除:{}key{}", this.cache.getName(), t.getId());
        }
    }

    private void deleteCacheIds(List<? extends ID> ids) {
        log.debug("从缓存删除多缓存ids");
        for (ID t : ids) {
            cache.evictIfPresent(t);
            log.debug("从缓存删除:{}key{}", this.cache.getName(), t);
        }
    }

//    @Async
    @Async("customizeThreadPool")
    @Override
    public void load(boolean isLoad) {
        log.debug("在自定义线程 {} 执行了缓存{}d的初始化加载过程", Thread.currentThread().getName(), this.cache.getName());

        if (isLoad) {
            List<T> l = this.findAll();
            for (T t : l) {
                cache.put(t.getId(), t);
            }
        }
    }

    @Override
    public BaseRepo<T, ID> getRepo() {
        return super.getRepo();
    }
}
